package org.kth.dks.test_bed;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.kth.dks.DKSObject;
import org.kth.dks.dks_comm.ConnectionManager;
import org.kth.dks.dks_comm.DKSOverlayAddress;
import org.kth.dks.dks_comm.DKSRef;
import org.kth.dks.dks_dht.DKSDHTImpl;
import org.kth.dks.util.CommunicationInfo;
import org.kth.dks.util.DKSPrintTypes;

import com.borland.jbcl.layout.XYConstraints;

/**
 * <p>Title: DKS_COMM</p>
 * <p>Description: DKS Communication Layer</p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: KTH-IMIT</p>
 * @author Hamid Reza Mizani (hrmizani@imit.kth.se)
 * @version 1.0
 */

public class TestBed_GUI extends JFrame {
	private final Logger log = Logger.getLogger(TestBed_GUI.class);
	ConnectionManager cm = null;
  DKSDHTImpl myDKSNode = null;
  DKSRef myDKSRef = null;
  RoutingTable rt = null;

  JButton jB_Exit = new JButton();
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JTextField jT_ID = new JTextField();
  JTextField jT_Port = new JTextField();
  JButton jB_Start = new JButton();
  JLabel jLabel3 = new JLabel();
  JLabel jL_IP = new JLabel();
  JScrollPane jScrollPane1 = new JScrollPane();
  JList jL_Nodes = new JList();
  JButton jB_Send = new JButton();
  JTextField jT_Send = new JTextField();
  JScrollPane jScrollPane2 = new JScrollPane();
  JTextArea jTA_Rec = new JTextArea();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel5 = new JLabel();
  JButton jB_SendXML = new JButton();
  JButton jButton1 = new JButton();
  JButton jB_Join = new JButton();
  JButton jB_Ring = new JButton();
  JButton jB_Leave = new JButton();
  JLabel jLabel6 = new JLabel();
  JTextField jT_Key = new JTextField();
  JLabel jLabel7 = new JLabel();
  JTextField jT_Value = new JTextField();
  JButton jButton2 = new JButton();
  JButton jB_Insert = new JButton();
  JButton jB_Search = new JButton();
  JButton jB_PrintBLandFL = new JButton();
  JButton jB_remove = new JButton();
  JTextField jT_url = new JTextField();
  JButton jB_Change = new JButton();
  JTextField jT_NewValue = new JTextField();

  public TestBed_GUI() {
    try {
      jbInit();
    }
    catch(Exception ex) {
      ex.printStackTrace();
    }
  }

  void jbInit() throws Exception {
    jB_Exit.setBounds(new Rectangle(252, 32, 73, 25));
    jB_Exit.setText("Exit");
    jB_Exit.addActionListener(new TestBed_GUI_jB_Exit_actionAdapter(this));
    this.getContentPane().setLayout(null);
    this.setLocale(java.util.Locale.getDefault());
    this.setTitle("DKS TestBed");
    jLabel1.setText("DKS ID:");
    jLabel1.setBounds(new Rectangle(54, 15, 47, 15));
    jLabel2.setText("Listening Port:");
    jLabel2.setBounds(new Rectangle(11, 36, 90, 15));
    jB_Start.setBounds(new Rectangle(252, 5, 73, 25));
    jB_Start.setText("Start");
    jB_Start.addActionListener(new TestBed_GUI_jB_Start_actionAdapter(this));
    jLabel3.setText("IP Address:");
    jLabel3.setBounds(new Rectangle(32, 57, 69, 15));
    jL_IP.setBorder(BorderFactory.createLineBorder(Color.black));
    jL_IP.setText("   ");
    jL_IP.setBounds(new Rectangle(108, 58, 127, 17));
    jB_Send.setBounds(new Rectangle(229, 311, 81, 25));
    jB_Send.setText("Send");
    jB_Send.addActionListener(new TestBed_GUI_jB_Send_actionAdapter(this));
    jT_Send.setText("");
    jT_Send.setBounds(new Rectangle(24, 314, 200, 19));
    jT_Send.addKeyListener(new TestBed_GUI_jT_Send_keyAdapter(this));
    jT_ID.setText("");
    jT_ID.setBounds(new Rectangle(108, 13, 54, 19));
    jT_Port.setText("");
    jT_Port.setBounds(new Rectangle(108, 35, 54, 19));
    jTA_Rec.setText("");
    jLabel4.setText("Select Node(s):");
    jLabel4.setBounds(new Rectangle(25, 77, 90, 15));
    jLabel5.setText("Message:");
    jLabel5.setBounds(new Rectangle(24, 247, 57, 15));
    jB_SendXML.setBounds(new Rectangle(252, 59, 73, 25));
    jB_SendXML.setText("XML");
    jB_SendXML.addActionListener(new TestBed_GUI_jB_SendXML_actionAdapter(this));
    jButton1.setBounds(new Rectangle(234, 193, 116, 25));
    jButton1.setToolTipText("");
    jButton1.setText("Print DKSURL");
    jButton1.addActionListener(new TestBed_GUI_jButton1_actionAdapter(this));
    jB_Join.setBounds(new Rectangle(26, 193, 59, 25));
    jB_Join.setText("Join");
    jB_Join.addActionListener(new TestBed_GUI_jB_Join_actionAdapter(this));
    jB_Ring.setBounds(new Rectangle(88, 193, 95, 25));
    jB_Ring.setText("Print Ring");
    jB_Ring.addActionListener(new TestBed_GUI_jB_Ring_actionAdapter(this));
    jB_Leave.setBounds(new Rectangle(26, 221, 69, 25));
    jB_Leave.setText("Leave");
    jB_Leave.addActionListener(new TestBed_GUI_jB_Leave_actionAdapter(this));
    jLabel6.setHorizontalAlignment(SwingConstants.RIGHT);
    jLabel6.setText("Key:");
    jLabel6.setBounds(new Rectangle(34, 376, 26, 15));
    jLabel7.setHorizontalAlignment(SwingConstants.RIGHT);
    jLabel7.setText("Value:");
    jLabel7.setBounds(new Rectangle(24, 398, 37, 15));
    jB_Insert.setText("Insert");
    jB_Insert.addActionListener(new TestBed_GUI_jB_Insert_actionAdapter(this));
    jT_Key.setText("");
    jT_Key.setBounds(new Rectangle(75, 375, 62, 19));
    jB_Insert.setBounds(new Rectangle(229, 366, 81, 25));
    jB_Insert.setMaximumSize(new Dimension(59, 23));
    jB_Insert.setPreferredSize(new Dimension(59, 23));
    jB_Insert.setMargin(new Insets(2, 14, 2, 14));
    jB_Insert.setText("Insert");
    jB_Search.setBounds(new Rectangle(229, 392, 81, 25));
    jB_Search.setText("Search");
    jB_Search.addActionListener(new TestBed_GUI_jB_Search_actionAdapter(this));
    jT_Value.setBounds(new Rectangle(74, 396, 151, 19));
    jScrollPane2.setBounds(new Rectangle(24, 263, 279, 47));
    jScrollPane1.setBounds(new Rectangle(24, 94, 326, 95));
    jB_PrintBLandFL.setBounds(new Rectangle(98, 222, 67, 25));
    jB_PrintBLandFL.setText("BL-FL");
    jB_PrintBLandFL.addActionListener(new TestBed_GUI_jB_PrintBLandFL_actionAdapter(this));
    jB_remove.setBounds(new Rectangle(229, 339, 81, 26));
    jB_remove.setMaximumSize(new Dimension(59, 23));
    jB_remove.setMinimumSize(new Dimension(59, 23));
    jB_remove.setPreferredSize(new Dimension(59, 23));
    jB_remove.setMargin(new Insets(2, 14, 2, 14));
    jB_remove.setText("Remove");
    jB_remove.addActionListener(new TestBed_GUI_jB_remove_actionAdapter(this));
    jT_url.setText("dksref://");
    jT_url.setBounds(new Rectangle(171, 225, 179, 20));
    jB_Change.setBounds(new Rectangle(28, 342, 96, 23));
    jB_Change.setText("Change to:");
    jB_Change.addActionListener(new TestBed_GUI_jB_Change_actionAdapter(this));
    jT_NewValue.setBounds(new Rectangle(127, 344, 89, 20));
    this.getContentPane().add(jLabel3, null);
    this.getContentPane().add(jT_ID, null);
    this.getContentPane().add(jT_Port, null);
    this.getContentPane().add(jLabel2, null);
    this.getContentPane().add(jLabel1, null);
    this.getContentPane().add(jL_IP, null);
    this.getContentPane().add(jB_SendXML, null);
    this.getContentPane().add(jB_Exit, null);
    this.getContentPane().add(jB_Start, null);
    this.getContentPane().add(jLabel4, null);
    this.getContentPane().add(jScrollPane1, null);
    this.getContentPane().add(jB_Ring, null);
    this.getContentPane().add(jScrollPane2, null);
    this.getContentPane().add(jLabel5, null);
    this.getContentPane().add(jB_Join, null);
    this.getContentPane().add(jB_Leave, null);
    this.getContentPane().add(jB_PrintBLandFL, null);
    this.getContentPane().add(jB_Send, null);
    this.getContentPane().add(jT_Send, null);
    this.getContentPane().add(jT_Key, null);
    this.getContentPane().add(jT_Value, null);
    this.getContentPane().add(jLabel6, null);
    this.getContentPane().add(jLabel7, null);
    this.getContentPane().add(jB_Search, null);
    this.getContentPane().add(jB_Insert, null);
    this.getContentPane().add(jB_remove, null);
    this.getContentPane().add(jButton1, null);
    this.getContentPane().add(jT_url);
    this.getContentPane().add(jB_Change);
    this.getContentPane().add(jT_NewValue);
    jScrollPane2.getViewport().add(jTA_Rec, null);
    jScrollPane1.getViewport().add(jL_Nodes, null);
    this.getContentPane().add(jB_Insert, new XYConstraints(229, 386, -1, -1));
  }

  public static void main(String[] args) {
    if (System.getProperty("log4jfile")!=null)
 	PropertyConfigurator.configure(System.getProperty("log4jfile"));
    if (args.length < 2) {
      System.out.println("Parameter: DKS_ID(int) port_number(int) [on/off]");
      System.out.println("	     on/off specifies whether logging should be on (default off)");
      System.exit(0);
    }
    TestBed_GUI testBed_GUI = new TestBed_GUI();
    testBed_GUI.jT_ID.setText( args[0] );
    testBed_GUI.jT_Port.setText( args[1] );
    String myip = "UnKnown Host";
    try {
      myip = InetAddress.getLocalHost().getHostAddress();
    }
    catch (UnknownHostException uhexp) {
      uhexp.printStackTrace();
    }
    testBed_GUI.jL_IP.setText( myip );
    testBed_GUI.setSize( 370, 460 );
    testBed_GUI.setVisible(true);
  }

  void jB_Exit_actionPerformed(ActionEvent e) {
    System.exit(0);
  }

  void jB_Start_actionPerformed(ActionEvent e) {
    int myid = Integer.parseInt(jT_ID.getText());
    int myport = Integer.parseInt(jT_Port.getText());
    String myip = jL_IP.getText();
    rt = new RoutingTable();
    try {

      myDKSRef = DKSRef.newDKSRef("dks://"+myip+":"+myport+"/0/"+myid+"/0");
      cm = ConnectionManager.getInstance(myport); // Static factory only used for testing, should use getInstance (singleton)
    myDKSNode = new DKSDHTImpl(cm, new DKSOverlayAddress( myid, 0, 0));
//      myDKSNode = DKSDHTImpl.createDKSDiskDHT(cm, new DKSOverlayAddress( myid, 0, 0));
      myDKSNode.logLevel(1);
      myDKSNode.create();
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    Vector nodes = rt.getAll();
    jL_Nodes.setListData( nodes );
  }

  public void ShowMsg( String str ) {
    jTA_Rec.append( str + "\n");
  }

  void jB_Send_actionPerformed(ActionEvent e) {
    if( jT_Send.getText().trim().length() == 0 )
      return;
    Object [] targets = jL_Nodes.getSelectedValues();
    for( int i = 0 ; i < targets.length ; i++ ) {
      StringTokenizer st = new StringTokenizer( (String)targets[i], "@" );
      int id = Integer.parseInt(st.nextToken());
      DKSRef node = rt.getDKSRef(id);
      //long myID = cm.getMyDKSRef().getID();
//      String xml = DKSMarshal.marshal( jT_Send.getText(), myID ); needs to be fixed
//      Message msg = new Message( xml.getBytes() );
//      cm.send(node, msg);
    }
    jT_Send.setText("");
  }

  void jT_Send_keyPressed(KeyEvent e) {
    if( e.getKeyCode() == e.VK_ENTER )
      jB_Send_actionPerformed(null);
  }

  void jB_SendXML_actionPerformed(ActionEvent e) {
    try {
      java.io.File ff = new java.io.File("input.xml");
      java.io.FileInputStream fis = new java.io.FileInputStream(ff);
      byte[] buff = new byte[ (int) ff.length()];
      fis.read(buff);
      jT_Send.setText( new String(buff) );
      jB_Send_actionPerformed(null);
    } catch(Exception e1) {
      e1.printStackTrace();
    }
  }

  void jButton1_actionPerformed(ActionEvent e) {
    System.out.println(myDKSNode.getDKSURL());
 //  cm.printBuffers(); // removed as there are now multiple buffers (one per dksnode)
 }

  void jB_Join_actionPerformed(ActionEvent e) {
    if( ! jT_url.getText().equalsIgnoreCase("dksref://") ) {
      DKSRef existingNode = null;
      try {
        existingNode = DKSRef.valueOf(jT_url.getText());
        myDKSNode.join(existingNode);
      }
      catch (MalformedURLException ex1) {
        ex1.printStackTrace();
      } catch (Exception ex) { System.err.println(ex); }

    } else {
      Object[] targets = jL_Nodes.getSelectedValues();
      DKSRef dest = null;
      if (targets.length == 1) {
        StringTokenizer st = new StringTokenizer( (String) targets[0], "@");
        int id = Integer.parseInt(st.nextToken());
        dest = rt.getDKSRef(id);
        try {
          myDKSNode.join(dest.getID(),
                         new URL("http://" + dest.getIP() + ":" + dest.getPort()));
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      } else {
        try {
          myDKSNode.join(0, null);
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    }
  }

  void jB_Ring_actionPerformed(ActionEvent e) {
    CommunicationInfo ci =  cm.getComInfo();
    System.out.println(ci);
  }

  void jB_Leave_actionPerformed(ActionEvent e) {
    myDKSNode.leave();//Leaving the DKS network!
  }

  void jB_Insert_actionPerformed(ActionEvent e) {
    long key = Long.parseLong( jT_Key.getText() );
    String value = jT_Value.getText();
    myDKSNode.addToBinding(key, new DKSObject(value.getBytes()));
    // ((DKS_DHT)myDKSNode).insert( key, new DKSObject(value.getBytes()) );
  }

  void jB_Search_actionPerformed(ActionEvent e) {
    long key = Long.parseLong( jT_Key.getText() );

    DKSObject [] result;
    result = myDKSNode.lookupBinding( key );
    if (result.length == 0) {
      jT_Value.setText("EMPTY");
    } else {
      log.debug("App svar:");
      String t = "";
      for( int i = 0 ; i < result.length ; i++ )
      {
        for (int xx=0; xx<result[i].getData().length; xx++)
        	log.debug(result[i].getData()[xx]);
        t = t + new String(result[i].getData()) + " ";
      }
      jT_Value.setText(t);
    }
  }

  void jB_PrintBLandFL_actionPerformed(ActionEvent e) {
    java.util.List fl = Arrays.asList(myDKSNode.myDKSImpl.getMyDKSNode().getNodeInfo().frontList);
    java.util.List bl = Arrays.asList(myDKSNode.myDKSImpl.getMyDKSNode().getNodeInfo().backList);
    System.out.println("frontlist: "+fl);
    System.out.println("backlist:  "+bl);
  }

  void jB_remove_actionPerformed(ActionEvent e) {
    long key = Long.parseLong( jT_Key.getText() );
    String value = jT_Value.getText();
    myDKSNode.removeFromBinding(key, new DKSObject(value.getBytes()));

    //long key = Long.parseLong(jT_Key.getText());
    //DKSObject obj = new DKSObject(jT_Value.getText().getBytes());

    // ((DKS_DHT)myDKSNode).remove(key, obj);
  }

  public void jB_Change_actionPerformed(ActionEvent e) {
    long key = Long.parseLong( jT_Key.getText() );
    String value1 = jT_Value.getText();
    String value2 = jT_NewValue.getText();
    myDKSNode.changeBinding(key, new DKSObject(value1.getBytes()),
                            new DKSObject( value2.getBytes() ) );
  }
}

class TestBed_GUI_jB_Change_actionAdapter
    implements ActionListener {
  private TestBed_GUI adaptee;
  TestBed_GUI_jB_Change_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }

  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Change_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Exit_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Exit_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }

  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Exit_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Start_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Start_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }

  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Start_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Send_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Send_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Send_actionPerformed(e);
  }
}

/* A thread to read incomming messages
 *
 */

class ReadMessages_GUI extends Thread {
  private ConnectionManager cm = null;
  private JTextArea jTA1 = null;

  ReadMessages_GUI( ConnectionManager newcm, JTextArea jta1 ) {
    this.cm = newcm;
    this.jTA1 = jta1;
    this.start();
    this.setName(ReadMessages_GUI.class.getName());
  }

  public void run() {
    while (true) {
//      CommBufferInElement buff = cm.receive(); // buffer replaced by multiple buffers
//      jTA1.append(buff.getDKSRef().getID() + ":" + buff.getMsg().getData() + "\n");
    }
  }
}

class TestBed_GUI_jT_Send_keyAdapter extends java.awt.event.KeyAdapter {
  TestBed_GUI adaptee;

  TestBed_GUI_jT_Send_keyAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void keyPressed(KeyEvent e) {
    adaptee.jT_Send_keyPressed(e);
  }
}

class TestBed_GUI_jB_SendXML_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_SendXML_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_SendXML_actionPerformed(e);
  }
}

class TestBed_GUI_jButton1_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jButton1_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jButton1_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Join_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Join_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Join_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Ring_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Ring_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Ring_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Leave_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Leave_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Leave_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Insert_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Insert_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Insert_actionPerformed(e);
  }
}

class TestBed_GUI_jB_Search_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_Search_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_Search_actionPerformed(e);
  }
}

class TestBed_GUI_jB_PrintBLandFL_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_PrintBLandFL_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_PrintBLandFL_actionPerformed(e);
  }
}

class TestBed_GUI_jB_remove_actionAdapter implements java.awt.event.ActionListener {
  TestBed_GUI adaptee;

  TestBed_GUI_jB_remove_actionAdapter(TestBed_GUI adaptee) {
    this.adaptee = adaptee;
  }
  public void actionPerformed(ActionEvent e) {
    adaptee.jB_remove_actionPerformed(e);
  }
}
